package com.example.demo.jeePay;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @ClassName OrderNoGenerator
 * @Description
 * @Author MingChang.Wei
 * @Date 2025/6/16
 **/
public class OrderNoGenerator {
    // 使用 SecureRandom 增强安全性
    private static final SecureRandom secureRandom = new SecureRandom();

    // 机器码，用于分布式系统，可通过配置文件或环境变量设置
    private static final String MACHINE_CODE = initMachineCode();

    // 自增序列，每个机器实例单独计数
    private static final AtomicInteger sequence = new AtomicInteger(0);

    // 序列最大值，防止溢出
    private static final int MAX_SEQUENCE = 9999;

    // 日期时间格式化器
    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");

    private static String initMachineCode() {
        try {
            // 获取 CPU 序列号（Windows/Linux）
            String cpuInfo = getCpuInfo();
            // 获取 MAC 地址
            String macAddress = getMacAddress();
            // 组合并哈希
            String combined = cpuInfo + macAddress;
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            byte[] hash = md.digest(combined.getBytes());

            // 提取前4字节并转换为无符号整数
            long code = ((long) (hash[0] & 0xFF) << 24) |
                    ((long) (hash[1] & 0xFF) << 16) |
                    ((long) (hash[2] & 0xFF) << 8) |
                    (long) (hash[3] & 0xFF);

            // 格式化为 4 位十六进制字符串（补前导零）
            return String.format("%04d", (code % 10000));
        } catch (Exception e) {
            return String.format("%04d", secureRandom.nextInt(10000));
        }
    }

    private static String getCpuInfo() {
        try {
            // Windows
            if (System.getProperty("os.name").contains("Windows")) {
                Process process = Runtime.getRuntime().exec("wmic cpu get ProcessorId");
                try (BufferedReader reader = new BufferedReader(
                        new InputStreamReader(process.getInputStream()))) {
                    reader.readLine(); // 跳过标题行
                    return reader.readLine().trim();
                }
            }
            // Linux
            else {
                Process process = Runtime.getRuntime().exec("cat /proc/cpuinfo | grep 'processor'");
                try (BufferedReader reader = new BufferedReader(
                        new InputStreamReader(process.getInputStream()))) {
                    return reader.readLine().trim();
                }
            }
        } catch (Exception e) {
            return "unknown";
        }
    }

    private static String getMacAddress() {
        try {
            NetworkInterface network = NetworkInterface.getByInetAddress(
                    InetAddress.getLocalHost());
            byte[] mac = network.getHardwareAddress();
            StringBuilder sb = new StringBuilder();
            for (byte b : mac) {
                sb.append(String.format("%02X", b));
            }
            return sb.toString();
        } catch (Exception e) {
            return "unknown";
        }
    }

    /**
     * 生成唯一订单号
     * 格式：时间戳(14位) + 机器码(4位) + 序列号(4位) + 随机数(4位)
     *
     * @return 订单号字符串
     */
    public static synchronized String generateOrderNumber() {
        // 获取当前时间戳
        String timestamp = LocalDateTime.now().format(FORMATTER);

        // 获取自增序列
        int seq = sequence.incrementAndGet();
        if (seq > MAX_SEQUENCE) {
            // 序列溢出时重置为 0
            sequence.set(0);
            seq = 0;
        }

        // 生成随机数
        int randomNum = secureRandom.nextInt(10000);

        // 组合成订单号
        return String.format("%s%04d%04d%04d",
                timestamp,
                Integer.parseInt(MACHINE_CODE) % 10000,
                seq,
                randomNum);
    }

    // 测试示例
    public static void main(String[] args) {
        // 测试生成 10 个订单号
        for (int i = 0; i < 5; i++) {
            System.out.println(generateOrderNumber());
        }
    }
}
